package com.wowoai.user.service.impl;

import cn.hutool.core.lang.Assert;
import com.wowoai.common.basemodule.BusinessException;
import com.wowoai.common.enums.ResponseEnum;
import com.wowoai.common.factoy.OssClientFactory;
import com.wowoai.common.userInfo.UserInfo;
import com.wowoai.user.controller.req.UserReq;
import com.wowoai.user.convert.UserConvert;
import com.wowoai.user.entity.ScoreOptionLogEntity;
import com.wowoai.user.entity.UserEntity;
import com.wowoai.user.enums.UserScoreOptionTypeEnum;
import com.wowoai.user.repository.ScoreOptionLogRepositoryI;
import com.wowoai.user.repository.UserRepositoryI;
import com.wowoai.user.service.UserServiceI;
import com.wowoai.user.service.dto.UserDTO;
import com.wowoai.utils.IdGeneratorUtil;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.Objects;

@Service
public class UserServiceImpl implements UserServiceI {
    private final UserRepositoryI userRepositoryI;
    private final ScoreOptionLogRepositoryI scoreOptionLogRepositoryI;
    private final OssClientFactory ossClientFactory;
    public UserServiceImpl(UserRepositoryI userRepositoryI, ScoreOptionLogRepositoryI scoreOptionLogRepositoryI, OssClientFactory ossClientFactory){
        Assert.notNull(userRepositoryI,"userRepositoryI 不能为空");
        Assert.notNull(scoreOptionLogRepositoryI,"scoreOptionLogRepositoryI 不能为空");
        Assert.notNull(ossClientFactory,"ossClientFactoy 不能为空");

        this.userRepositoryI = userRepositoryI;
        this.scoreOptionLogRepositoryI = scoreOptionLogRepositoryI;
        this.ossClientFactory = ossClientFactory;
    }



    @Override
    public UserDTO getUserByPhoneNumber(String phoneNumber) {
        UserEntity byPhoneNumber = userRepositoryI.findByPhoneNumber(phoneNumber);
        if (Objects.isNull(byPhoneNumber)) {
            throw new BusinessException(ResponseEnum.NO_AUTH.getCode(), "用户不存在");
        }
        return UserConvert.INS.entity2DTO(byPhoneNumber);
    }

    @Override
    public UserDTO loginAndRegister(UserReq userReq) {
        UserEntity userEntity = userRepositoryI.findByPhoneNumber(userReq.getPhoneNumber());
        if (Objects.isNull(userEntity)) {
            //木有用户则新增注册
            Long id = IdGeneratorUtil.nextId();
            userEntity = UserEntity.create(id);
            userEntity.setLastLoginTime(System.currentTimeMillis());
            userEntity.setPhoneNumber(userReq.getPhoneNumber());
            userEntity = userRepositoryI.save(userEntity);
        } else {
            //有用户更新登录时间
            userEntity.setLastLoginTime(System.currentTimeMillis());
            userRepositoryI.update(userEntity);
        }
        return UserConvert.INS.entity2DTO(userEntity);
    }

    /**
     * 减积分逻辑
     *
     * @param userDTO        用户信息
     * @param score          扣减的积分数
     * @param optionTypeEnum 操作类型
     * @param optionValue    操作值
     */
    @Transactional
    @Override
    @Async
    public void updateScore(UserDTO userDTO, Integer score, UserScoreOptionTypeEnum optionTypeEnum, String optionValue) {
        UserEntity userEntity = userRepositoryI.findByPhoneNumber(userDTO.getPhoneNumber());
        if (Objects.isNull(userEntity)) {
            throw new BusinessException(ResponseEnum.NO_AUTH.getCode(), "用户不存在");
        }
        if ((userEntity.getScore() + userEntity.getPermanentScore()) < score) {
            throw new BusinessException(ResponseEnum.SUBTRACT_SCORE_FAIL.getCode(), "用户积分不足");
        }
        userEntity.setModifyTime(System.currentTimeMillis());
        userEntity.setModifierId(userDTO.getId());
        userEntity.setModifierName(userDTO.getNickName());
        //减去积分逻辑
        this.calculateSubtract(userEntity, score);
        userRepositoryI.update(userEntity);

        this.addOptionLog(userEntity,optionTypeEnum,optionValue);
    }

    /**
     * 增加记录
     */
    @Async
    protected void addOptionLog(UserEntity userEntity, UserScoreOptionTypeEnum optionTypeEnum, String optionValue) {
        ScoreOptionLogEntity scoreOptionLogEntity = ScoreOptionLogEntity.create(IdGeneratorUtil.nextId(), userEntity.getCreatorId(), userEntity.getCreatorName());
        scoreOptionLogEntity.setOptionType(optionTypeEnum.getCode());
        scoreOptionLogEntity.setOptionTypeName(optionTypeEnum.getTypeName());
        scoreOptionLogEntity.setOptionValue(optionValue);
        scoreOptionLogEntity.setUserId(userEntity.getId());
        scoreOptionLogEntity.setUserName(userEntity.getNickName());
        scoreOptionLogEntity.setPhoneNumber(userEntity.getPhoneNumber());
        scoreOptionLogRepositoryI.save(scoreOptionLogEntity);
    }

    /**
     * 计算减去积分的逻辑
     *
     * @param userEntity 临时积分,永久积分
     * @param subScore       要进去的积分
     */
    private void calculateSubtract(UserEntity userEntity, Integer subScore) {
        int score = userEntity.getScore();
        int permanentScore = userEntity.getPermanentScore();
        //优先减去临时积分
        if (userEntity.getScore() >= subScore) {
            //当前临时积分大于要减去的积分直接减去
            userEntity.setScore(score - subScore);
        }else {
            //如果临时积分不够减则要在永久积分上去减去
            permanentScore += userEntity.getScore() - subScore; // 等于 ：永久积分 - (-result)
            //因为之前的判断已经表明积分绝对够剪所以这里直接赋值
            userEntity.setPermanentScore(permanentScore);
            //如果到这里临时积分肯定是0了
            userEntity.setScore(0);
        }
    }

    @Override
    public void tipsSuccess(String phoneNumber) {
        UserEntity userEntity = userRepositoryI.findByPhoneNumber(phoneNumber);
        userEntity.setScoreTagFlag(Boolean.FALSE);
        userRepositoryI.update(userEntity);
    }

    @Override
    public UserDTO getUserById(Long userId) {
        UserEntity userEntity = userRepositoryI.findById(userId);
        if (Objects.isNull(userEntity)){
          throw new BusinessException("查询用户不存在");
        }
       return UserConvert.INS.entity2DTO(userEntity);
    }

    @Override
    public UserDTO updateUserInfo(UserReq userReq, UserInfo userInfo) {
        UserEntity userEntity = userRepositoryI.findByPhoneNumber(userInfo.getPhoneNumber());
        if (Objects.isNull(userEntity)){
            throw new BusinessException("查询用户不存在");
        }
        MultipartFile file = userReq.getAvatar();
        if (Objects.nonNull(file)){
            String avatar = ossClientFactory.upload(file, "headSculpture",null);
            if (!StringUtils.hasText(avatar)){
                throw new BusinessException("头像更新失败");
            }
            userEntity.setAvatar(avatar);
        }
        if (Objects.nonNull(userReq.getNickName())){
            userEntity.setNickName(userReq.getNickName());
        }
        if (Objects.nonNull(userReq.getGender())){
            userEntity.setGender(userReq.getGender());
        }
        userEntity.setModifyTime(System.currentTimeMillis());
        userEntity.setModifierId(userInfo.getUserId());
        userEntity.setModifierName(userInfo.getUserName());
        userRepositoryI.update(userEntity);

        return UserConvert.INS.entity2DTO(userEntity);
    }

    @Override
    public Boolean addScore(UserInfo userInfo, Integer score, Integer permanentScore, UserScoreOptionTypeEnum userScoreOptionTypeEnum) {
        UserEntity userEntity = userRepositoryI.findByPhoneNumber(userInfo.getPhoneNumber());
        if (Objects.isNull(userEntity)){
            throw new BusinessException("查询用户信息失败");
        }
        if (Objects.equals(userEntity.getAdCount() ,15)){
            throw new BusinessException("请明天再来！");
        }
        Integer nowPermanentScore = Objects.isNull(userEntity.getPermanentScore()) ? 0 : userEntity.getPermanentScore();
        Integer nowScore = Objects.isNull(userEntity.getScore()) ? 0 : userEntity.getScore();
        userEntity.setPermanentScore(nowPermanentScore + permanentScore);
        userEntity.setScore(nowScore + score);
        userEntity.setModifyTime(System.currentTimeMillis());
        int adCount = Objects.isNull(userEntity.getAdCount()) ? 0 : userEntity.getAdCount();
        userEntity.setAdCount(adCount + 1);
        userRepositoryI.update(userEntity);
        //加积分操作记录
        this.addOptionLog(userEntity,userScoreOptionTypeEnum,"+10");
       return Boolean.TRUE;
    }
}
